// 用户认证事务测试 - TypeScript版本
import argon2 from 'argon2';
import sequelize from '../src/lib/database';
import User from '../src/models/user';

// 测试配置
const TEST_USER = {
  username: 'testuser',
  password: 'testpassword123',
  email: 'test@example.com'
};

// 全局变量
let transaction: any = null;

async function setupDatabase() {
  try {
    // 测试数据库连接
    await sequelize.authenticate();
    console.log('✅ 数据库连接成功');
    
    // 自动创建表（如果不存在）
    await User.sync({ alter: true });
    console.log('✅ 用户表创建/更新成功');
    
  } catch (error) {
    console.error('❌ 数据库设置失败:', error);
    process.exit(1);
  }
}

async function runTestInTransaction(testName: string, testFunction: () => Promise<void>) {
  try {
    console.log(`\n=== 开始测试: ${testName} ===`);
    
    // 开始事务
    transaction = await sequelize.transaction();
    
    // 执行测试函数
    await testFunction();
    
    // 回滚事务
    await transaction.rollback();
    console.log(`✅ 测试通过: ${testName}`);
    console.log('✅ 事务已回滚，数据恢复原状');
    
  } catch (error) {
    // 发生错误时也回滚事务
    if (transaction) {
      await transaction.rollback();
      console.log('✅ 事务已回滚，数据恢复原状');
    }
    console.error(`❌ 测试失败: ${testName}`, error);
    throw error;
  } finally {
    transaction = null;
  }
}

async function testUserCreationAndEncryption() {
  // 测试1: 创建用户并验证密码加密
  console.log('创建测试用户...');
  
  // 在事务中创建用户
  const user: any = await User.create({
    username: TEST_USER.username,
    password_hash: await argon2.hash(TEST_USER.password),
    email: TEST_USER.email
  }, { transaction });
  
  console.log(`用户创建成功，ID: ${user.id}`);
  
  // 验证用户是否存在
  const foundUser: any = await User.findOne({ 
    where: { username: TEST_USER.username },
    transaction 
  });
  
  if (!foundUser) {
    throw new Error('用户创建后未找到');
  }
  
  console.log(`用户查找成功: ${foundUser.username}`);
  
  // 验证密码哈希格式 (Argon2格式)
  if (!foundUser.password_hash.startsWith('$argon2id$')) {
    throw new Error('密码哈希格式不正确');
  }
  
  console.log('密码哈希格式验证通过');
  
  // 验证密码加密是否有效
  const isPasswordValid = await argon2.verify(foundUser.password_hash, TEST_USER.password);
  if (!isPasswordValid) {
    throw new Error('密码加密验证失败');
  }
  
  console.log('密码加密验证通过');
}

async function testUserLogin() {
  // 测试2: 用户登录验证
  console.log('准备登录测试...');
  
  // 先在事务中创建一个测试用户
  const user: any = await User.create({
    username: TEST_USER.username,
    password_hash: await argon2.hash(TEST_USER.password),
    email: TEST_USER.email
  }, { transaction });
  
  console.log(`测试用户创建成功: ${user.username}`);
  
  // 模拟登录过程
  console.log('开始登录验证...');
  
  // 1. 查找用户
  const foundUser: any = await User.findOne({ 
    where: { username: TEST_USER.username },
    transaction 
  });
  
  if (!foundUser) {
    throw new Error('登录失败: 用户不存在');
  }
  
  // 2. 验证正确密码
  const isCorrectPassword = await argon2.verify(foundUser.password_hash, TEST_USER.password);
  if (!isCorrectPassword) {
    throw new Error('登录失败: 正确密码验证失败');
  }
  
  console.log('✅ 正确密码登录验证通过');
  
  // 3. 验证错误密码
  const isWrongPassword = await argon2.verify(foundUser.password_hash, 'wrongpassword123');
  if (isWrongPassword) {
    throw new Error('登录失败: 错误密码验证失败');
  }
  
  console.log('✅ 错误密码登录验证通过');
  
  // 4. 验证不存在的用户登录
  const nonExistentUser = await User.findOne({ 
    where: { username: 'nonexistentuser' },
    transaction 
  });
  
  if (nonExistentUser) {
    throw new Error('登录失败: 不存在的用户不应被找到');
  }
  
  console.log('✅ 不存在用户登录验证通过');
}

async function testCleanup() {
  // 验证事务回滚后数据是否被清除
  console.log('\n=== 验证事务回滚结果 ===');
  
  // 在事务外查询，应该找不到测试用户
  const user = await User.findOne({ where: { username: TEST_USER.username } });
  
  if (user) {
    console.error('❌ 错误: 事务回滚失败，测试用户仍然存在');
    // 手动清理
    await user.destroy();
    console.log('已手动清理测试用户');
  } else {
    console.log('✅ 事务回滚成功，测试用户已被清除');
  }
}

async function runAllTests() {
  try {
    // 设置数据库
    await setupDatabase();
    
    // 运行测试用例
    await runTestInTransaction('用户创建和密码加密', testUserCreationAndEncryption);
    await runTestInTransaction('用户登录验证', testUserLogin);
    
    // 验证清理结果
    await testCleanup();
    
    console.log('\n🎉 所有测试通过！');
    
  } catch (error) {
    console.error('\n❌ 测试执行失败:', error);
    process.exit(1);
  } finally {
    // 关闭数据库连接
    await sequelize.close();
    console.log('\n📌 数据库连接已关闭');
  }
}

// 执行测试
runAllTests();
